package cc.shacocloud.redis.study.util.redis;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import redis.clients.jedis.*;
import redis.clients.jedis.util.SafeEncoder;

import java.util.*;
import java.util.function.Function;

/**
 * {@linkplain BuilderFactory} 的拓展，对redis的返回结果进行二次封装，转换为我们需要的数据格式
 */
public class BuilderFactoryExpand {

    /**
     * 结果转string
     */
    public static final Function<Object, String> TO_STRING = obj -> {
        if (obj == null) return null;

        if (obj instanceof byte[]) {
            return SafeEncoder.encode((byte[]) obj);
        } else {
            return String.valueOf(obj);
        }
    };

    public static final Builder<Long> LONG = new Builder<Long>() {

        @Nullable
        @Override
        public Long build(Object data) {
            final String str = TO_STRING.apply(data);
            return str == null ? null : Long.parseLong(str);
        }

        @NotNull
        @Contract(pure = true)
        public String toString() {
            return "Long";
        }
    };

    /**
     * {@linkplain Jedis#eval}方法返回值为hash时使用
     */
    public static final Builder<Map<String, String>> EVAL_STRING_MAP = new Builder<Map<String, String>>() {

        @Override
        public Map<String, String> build(Object data) {
            return evalResult(data);
        }

        @NotNull
        @Contract(pure = true)
        @Override
        public String toString() {
            return "Map<String, String>";
        }

        @Contract("null -> null")
        @SuppressWarnings("unchecked")
        private Map<String, String> evalResult(Object result) {
            if (result == null) return null;
            final List<Object> flatHash = (List<Object>) result;
            final Map<String, String> hash = new HashMap<>(flatHash.size() / 2, 1);
            final Iterator<Object> iterator = flatHash.iterator();
            while (iterator.hasNext()) {
                hash.put(TO_STRING.apply(iterator.next()), TO_STRING.apply(iterator.next()));
            }
            return hash;
        }

    };

    /**
     * 通用
     */
    public static final Builder<Object> COMMON = new Builder<Object>() {

        @Override
        public Object build(Object data) {
            return evalResult(data);
        }

        private Object evalResult(Object result) {
            if (result instanceof byte[]) return SafeEncoder.encode((byte[]) result);

            if (result instanceof List<?>) {
                List<?> list = (List<?>) result;
                List<Object> listResult = new ArrayList<>(list.size());
                for (Object bin : list) {
                    listResult.add(evalResult(bin));
                }

                return listResult;
            }

            return result;
        }
    };
}
